Web Apps in R Using Shiny

Steven Mortimer
March 21, 2017

What is Shiny?

  • A web application framework for R
  • Written by Joe Cheng and RStudio
  • First CRAN package up in 2012
  • Delivers interactive experience over the web, all written in R!
  • Ready for the enterprise

Show me Shiny!

Prerequisites

  1. R and RStudio
  2. Intermediate Understanding of R
    • Import/Export data, dplyr, ggplot
  3. HTML, CSS, JavaScript not required, but helpful
  4. Strategy for sharing (Markdown/Pres, Hosted/Private)


The shiny package!

Bare Minimum Project Structure

Create a folder for your app and put all related files inside that folder. At minimum every Shiny app contains 2 parts:

  1. A UI (client-side). Specified in a file called ui.R
  2. Server Logic (server-side). Specified in a file called server.R

NOTE: You can create a “single-file” Shiny app that puts the UI and Server code in the same file and runs, but this is typically for toy examples and reprex. This is not recommended in production. See this article for more detail: Single-file Shiny apps.

Recommended Project Structure

Take the bare minimum and add the following three items to your folder:

  1. A file called global.R - Main location for loading packages, sharing data between ui and server sides, etc. 1
  2. A folder called www - Main location for all web resources in your application. If you would like to enforce a global standard of styling, then create a .css file containing a style sheet language for formatting.2
  3. A folder called data - Main location for all data that your app uses. Especially important if not connecting to a database.

shinyUI()

A ui.R file - holds the client-side logic

library(shiny) shinyUI( fluidPage( titlePanel('Revenue Prediction from Marketing Expenditures'), sidebarLayout( sidebarPanel( sliderInput(inputId = 'spend', label = 'Expenditure Level in $K:', min = 54, max = 481, value = 250) ), mainPanel( plotOutput('prediction_plot') ) ) ) )

shinyServer()

A server.R file - holds the server-side logic

library(shiny) revenue <- read.csv('./data/marketing.csv') model <- lm(revenues ~ marketing_total, data = revenue) shinyServer(function(input, output) { output$prediction_plot <- renderPlot({ newdata <- data.frame(marketing_total = input$spend) pred <- predict(model, newdata, interval = 'predict') plot(revenue$marketing_total, revenue$revenues, xlab = 'Marketing Expenditures ($K)', ylab = 'Revenues ($K)') abline(model, col = 'blue') points(input$spend, pred[1], pch = 19, col = 'blue', cex = 2) points(c(rep(input$spend, 2)), c(pred[2], pred[3]), pch = '-', cex = 2, col = 'orange') segments(input$spend, pred[2], input$spend, pred[3], col = 'orange', lty = 2, lwd = 2) }) })

The Result?

shiny::runGitHub(repo = "com.packtpub.intro.r.bi",
                 username = "StevenMMortimer",
                 subdir = "Chapter8-ShinyDashboards/Ch8-BasicShinyApp")

What's Really Happening

reactivity


In the ui.R:

sliderInput(inputId = 'spend', label = 'Expenditure Level in $K:', min = 54, max = 481, value = 250) )

In the server.R:

shinyServer(function(input, output) { output$prediction_plot <- renderPlot({ newdata <- data.frame(marketing_total = input$spend) …

Recap of the basics

  1. One folder with ui.R, server.R, and other files and folders
    • All client-side elements go in ui.R
    • All server-side logic goes in server.R
  2. Inputs and Outputs passed between
    • ui.R provides input$ that server.R accesses
    • server.R provides output$ that ui.R displays
  3. reactivity invalidates cached values on server when inputs change1

Understanding the Grid Layout

Shiny includes a grid-based layout framework based on the Bootstrap project.1

shinyUI(fluidPage( fluidRow( column(12, 'Fluid 12', fluidRow( column(6, 'Fluid 6', fluidRow( column(6, …

Tips for the User Experience

The head tag - The head tag identifies a portion of the web page, usually not visible to the user, which contains the application title, icon, metadata, and scripts.

tags$head(
  tags$link(rel = "stylesheet", type = "text/css", 
            href = "app-styling.css")
)

The progress wheel - Lets the user know that app is processing their input.

shinysky::busyIndicator(text = "Calculation in progress ... ", wait = 0)

Custom JavaScript1 & shinyjs - Extends interactivity and experience

More Cool Stuff

Google Analytics Tracking - Setup an account and Google will give you Javascript snippet to embed to track users.

tags$script("
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-XXXXXXXX-1', 'auto');
ga('send', 'pageview');
")

Connecting to a database - Just like connecting to database from R or RStudio…

library(RPostgreSQL)
con <- dbConnect(dbDriver("PostgreSQL"), dbname = "postgres",
                 host = "localhost", port = 5432,
                 user = "user", password = 'password')
app_dat <- dbGetQuery(conn=con, statement="SELECT * FROM app.dat")
dbDisconnect(con)

shinyServer(function(input, output) {
...

And More Cool Stuff

The DT package - Highly interactive, functional tables based on

More examples available on https://rstudio.github.io/DT/

Running Shiny Apps

  • Located on GitHub, in a Gist, or archived (e.g. .tar.gz)

Those options explained in more detail here

shiny::runGitHub(repo = "com.packtpub.intro.r.bi",
                 username = "StevenMMortimer",
                 subdir = "Chapter8-ShinyDashboards/Ch8-CampaignCreatorApp")


https://reportmort.shinyapps.io/campaign-creator-app/

  • Hosted on a private server

Happy App-ing with Shiny!